Электронное голосование — что это такое?
Электронное голосование — а зачем оно?
Создание и подготовка базы данных
Интеграция системы в уже готовый сайт
Главная страничка (файл Vindex.asp)
Рассмотренные нами в предыдущих частях настоящей статьи примеры в той или иной степени представляли собой разнообразные интерфейсы к базам данных. А такая задача как разработка системы электронного голосования, нами пока не рассматривалась. В настоящей статье представлен материал, который позволит самостоятельно разработать такую систему, а также рассмотрен вопрос об организации переносимых модулей, позволяющих обеспечить легкое и удобное встраивание такой системы практически в любой сайт независимо от его сложности.
Разумеется, речь идет о наиболее типичной системе электронного голосования. Прежде всего — это система, предлагающая пользователю вопрос и несколько наиболее типичных вариантов ответа на него. Кроме того, это система сбора данных (обработки пользовательского ввода) и выдачи интегральных результатов голосования как в численном, так и в графическом представлении.
Сама система выбора того или иного варианта ответа может быть представлена как посредством логики «или», так и логики «и». Другими словами, в зависимости от того, допустим выбор более чем одного варианта ответа на поставленный вопрос или нет, может применяться одна из двух схем анализа ответа и соответственно один из двух компонентов формы опроса («радиокнопки» или «чекбоксы»). Но об этом чуть позже, а для начала все-таки уясним, какую выгоду может дать организация системы электронного голосования на вашем сайте.
Этот тривиальный вопрос может возникнуть у многих читателей. Во-первых, система электронного голосования может пробудить интерес к вашему сайту (например, пользователи вашего сайта могут пригласить поучаствовать в голосовании своих знакомых или коллег). Здесь наиболее существенным является постановка самой задачи голосования. Нередки случаи, когда вопрос выбирается с таким расчетом, чтобы втянуть отвечающих на него в дискуссию на форуме или в чате на том же сайте. Это делается специально для повышения активности сайта. Представьте себе, что вопрос звучит, к примеру так: «Сотовым телефоном какого производителя вы пользуетесь?» или «Доверяете ли вы президенту?». Таким образом, правильная постановка и выбор самого вопроса является мощным инструментом привлечения внимания к тому или иному сайту и в удачном сочетании с другим функционалом может обеспечить реальный успех в его продвижении.
Разумеется, предполагается, что читатель знаком с основами ASP- и SQL-программирования (первых частей настоящей статьи для этого будет вполне достаточно). Кроме того, нам потребуется Microsoft SQL Server 7.0 или 2000, какой-нибудь HTML- или текстовый редактор (рекомендую использовать Macromedia Dreamweaver UltraDev 4.0) и немного терпения.
Создадим две таблицы: таблицу вопросов (VQuestions) и таблицу ответов (VAnswers). В таблице ответов заведем поле (Total) для регистрации количества полученных ответов. Представим себе их взаимосвязь так, как показано на рисунке.
Ключевыми здесь являются столбцы ID. A взаимосвязь столбца QuestionID таблицы ответов с столбцом ID таблицы вопросов, по сути, отражает взаимосвязь вопросов и ответов.
Далее необходимо прописать нашу базу данных в соответствующем разделе источников данных системы. Для этого сделайте следующее:
Voter SQL Server
Теперь, когда база данных готова, можно переходить к созданию самой системы электронного голосования.
Однако сначала необходимо уяснить еще один вопрос. Каким именно образом будет выбираться тот или иной вопрос из базы данных, ведь в общем случае (а мы рассмотрим именно его) вопросов в базе может быть несколько.
Для этого мы будем каждый раз выбирать тот или иной вопрос из базы данных случайным образом (с помощью генератора случайных значений).
Дело в том, что само по себе голосование не имеет смысла. Посудите сами, кому нужен сайт, предназначенный исключительно для системы электронного голосования. С другой стороны, интеграция его в уже готовый сайт «в чистом виде» может создать сложности — как для восприятия исходного текста, так и в дальнейшем, например, если потребуется временно отключить голосование. Поэтому попытаемся разработать систему таким образом, чтобы ее интеграция в уже готовый сайт не составила труда. Для этого необходимо сформировать независимый модуль системы и «включить» его в текст основного сайта там, где это необходимо. Так, к примеру, текст страницы вашего сайта может выглядеть следующим образом:
<head> <title>ASP на блюдечке (Часть - 14) - Разработка системы электронного голосования</title> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> </head> <body marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" > … <!-- #include file="Vindex.asp"--> … </body> </html>
или
<!-- #include file="mainheader.inc"--> <!-- #include file="Vindex.asp"--> <!-- #include file="mainfooter.inc"-->
Как видите, в первом случае директива о включении странички с системой голосования (<!-- #include file="Vindex.asp"-->) указана в необходимом месте. Во втором случае страничка исходного сайта представлена в виде трех последовательно «включаемых» элементов: начала, странички с голосованием и конца. Использование того или иного способа организации структуры странички вашего сайта — дело вкуса и зависит от структуры исходного сайта, а также от степени его сложности.
Прежде всего необходимо разработать страничку, осуществляющую показ вопроса и вариантов ответов на него (здесь и далее мы будем использовать логическую схему «или» для получения ответа пользователей). Для этого сначала напишем пару функций для осуществления соединения с базой данных и отключения от нее:
<% Sub Connect() dsn = "DSN=Voter; UID=sa;PWD=;database=Voter" Set conn = Server.createobject("adodb.connection") Set rs = Server.createobject("adodb.recordset") conn.open dsn End Sub Sub Close() rs.close set rs=nothing conn.close set conn=nothing End Sub %>
Далее нам потребуется функция извлечения ответов на данный вопрос. Она будет служить для выборки соответствующих ответов с последующим формированием элементов интерфейса пользовательской формы на их основе:
<% Sub FindAns(QID) call connect() sql="SELECT id, ansdesc FROM VAnswers WHERE QuestionID = " & QID & " ORDER BY id" rs.open sql,conn End Sub %>
Теперь установим опции «предзагрузки» пяти изображений, соответствующих пяти возможным вариантам ответов пользователей, которые будут служить для графической интерпретации ответов пользователей (изображения подготовим заранее).
<html> <head> <script> img1 = new Image(); img1.src = "images/Voter/char1.gif"; img2 = new Image(); img2.src ="images/Voter/char2.gif"; img3 = new Image(); img3.src = "images/Voter/char3.gif"; img4 = new Image(); img4.src = "images/Voter/char4.gif"; img5 = new Image(); img5.src = "images/Voter/char5.gif"; …
Определим функцию, которая будет перемещать пользователя на страничку просмотра результатов голосования, причем передадим ей в качестве параметра action значение view:
… function gotoResults() { location.href="Voter.asp?action=view" } </script> <title> </title> </head> …
Далее создадим главную форму для пользовательского ввода, определим скрип-реакцию на нее и при этом передадим ей в качестве параметра action значение vote:
… <body> <form action="Voter.asp?action=vote" method="post"> <table border=0 border=0 cellpadding="0" cellspacing="0"> <tr> <td colspan=2> …
Теперь извлечем максимальное значение ключевого поля ID из таблицы вопросов, с тем чтобы получить предел генерации случайных чисел, которым мы будем руководствоваться для выработки псевдослучайного значения:
… <% Dim sSQL, Sql, Que, Rs, Rs1, Conn, Dsn, LastID, RndValue, I Call Connect() Sql = "SELECT MAX(ID) AS LastID FROM VQuestions" Rs.open Sql, Conn LastID = Rs("LastID") Call Close() …
Затем сгенерируем случайное значение в пределах от 1 до полученного максимального значения:
… RndValue = Int(LastID * Rnd + 1) …
И выберем из таблицы соответствующий вопрос:
… Call Connect() Sql = "select que from VQuestions where id = " & CStr(RndValue) Rs.open Sql, Conn que = rs("que") Call Close() Session ("QuestionID") = RndValue %> …
Покажем вопрос пользователю, извлечем (с помощью вышеупомянутой функции) значения его ответов и построим форму для регистрации ответа пользователя. Для этого в цикле будем формировать тег вида <input type=radio name="poll" value="Ответ">:
… <b><font size="-2" color="black" face="verdana,arial,sans-serif"> Примите участие в нашем голосовании, ответьте на вопрос:<br> <%= que %> </font> </b> </tr></td> </table> <table border=0 border=0 cellpadding="0" cellspacing="0"> <tr> <% Call FindAns(RndValue) I = 1 Do while not rs.eof %> <td> <input type=radio name="poll" value='<%= rs("id") %>' <% If I = 1 Then Response.Write "Checked"%> > <i><font size="-3" color="black" face="verdana,arial,sans-serif"> <%=rs("ansdesc") %> </font></i></td> <% I = I + 1 rs.movenext Loop call close() %> </tr> <tr><td colspan=2> <input type="hidden" name="quet" value='<%=que%>'> <input type="Submit" name="submit" value="Голосовать" Style="font: 7pt 'Verdana'; Width: 65; Height: 18"> <input type="button" value="Результаты" onclick="gotoResults()" Style="font: 7pt 'Verdana'; Width: 68; Height: 18"> </td> </tr> </table> </form> </body> </html>
Обработка результатов голосования (файл Voter.asp)
Для того чтобы результат формировался в той же страничке нашего основного сайта, можно по аналогии с вышеизложенной структурой «облечь» страничку обработки результатов голосования во «включения» файлов подстраничек заголовка вначале и концевика в конце соответственно:
<!-- #include file="mainheader.inc"--> <% dim dsn,conn,sql,rs dim useraction,ansid,sql1 dim ansdesc,newtotal,total,iTotal,t,ImageWidth dim sql_statement dim ors,rs2,ans dim final_total dim ansimage dim votetwice,already,msg,ansPercent Sub Connect() dsn = "DSN=Voter; UID=sa;PWD=;database=Voter" Set conn=server.createobject("adodb.connection") Set rs=server.createobject("adodb.recordset") conn.open dsn End Sub Sub Close() rs.close set rs = nothing conn.close set conn = nothing End Sub …
Далее выясним, «каким путем» пользователь попал на данную страничку. Здесь возможны два значения: vote — пользователь проголосовал, и view — пользователь уже голосовал и необходимо показать ему результаты голосования:
… useraction = request("action") Select Case useraction case "vote" response.write request.form("quet") & "<br><br>" …
Посредством булевой переменной voteTwice можно управлять процессом голосования. В частности, установив ее значение в false, можно разрешить пользователям голосовать свободно и независимо от того, голосовал данный пользователь ранее или нет. В противном случае система не будет позволять одному и тому же пользователю голосовать повторно.
В случае недопустимого повторного голосования переадресуем пользователя на ту же страничку (замкнем страничку на самой себе) с параметром action, равным view, и с дополнительным параметром, свидетельствующим об ошибке msg=1:
… voteTwice = false Select Case voteTwice Case true If Request.Cookies("poll_1")="" Then Response.Cookies("poll_1")="already" Response.Cookies("poll_1").Expires = Date + 365 Else Response.Redirect "Voter.asp?action=view&msg=1" End If End Select …
Далее прочитаем ответ пользователя и обновим общее количество ответов на данный вопрос в соответствии с выбранным пользователем вариантом:
… ansid = Request("poll") Call Connect() sql = "SELECT * FROM VAnswers WHERE id = " & ansid rs.open sql,conn total = rs("total") total = total + 1 sql1 = "UPDATE VAnswers SET total = " & total & " WHERE id = " & ansid conn.execute(sql1) rs.close set rs = nothing %> …
Включим подстраничку показа результатов голосования:
… <!--#include file="VShowRes.asp"--> <% case "view" …
Обработаем параметр msg и в случае ошибки выдадим предупреждение пользователю о недопустимости повторного голосования:
… msg = request("msg") If msg <> "" Then Response.Write "<font size='-2' color='red' face='verdana,arial,sans-serif'>" Response.Write "<br><br><b>Повторное голосование недопустимо!</b></font><br><br>" End If Call Connect() %> <!--#include file="VShowRes.asp"--> <% conn.close set conn = nothing end select %> <!-- #include file="mainfooter.inc"-->
Как видите, процесс проверки повторного голосования пользователей довольно прост. Для этого используется механизм cookies («ключиков»).
Просмотр результатов голосования (файл VShowRes.asp)
Нам осталось подготовить страничку, формирующую результаты голосования в графической форме. Для этого сначала вычислим сумму всех количеств данных ответов на один и тот же вопрос (идентификатор вопроса будем читать из сессионной переменной):
… <% sql_statement = "SELECT SUM(total) FROM VAnswers WHERE QuestionID = " & Session ("QuestionID") Set oRs = Server.CreateObject("ADODB.recordset") oRs.Open sql_statement,Conn final_total = oRs(0).value ors.close set ors = nothing …
А теперь выберем все варианты ответов на данный вопрос и покажем их пользователю, предварительно задав ширину картинок со столбиками соответствующих ответов и сформировав процентное отношение ответов к их общему числу для каждого их варианта:
… sql = "SELECT * FROM VAnswers WHERE QuestionID = " & Session ("QuestionID") & " ORDER BY id" set Rs2 = conn.execute(sql) Response.Write "<b><font size='-2' color='black' face='verdana,arial,sans-serif'>" Response.Write "Результаты голосования</font></b><br>" Response.Write "<table border=1 cellspacing='0'>" t = 1 Do While Not rs2.eof ans = rs2("total") If ans = 0 Then ansPercent = "0%" Else ansPercent = formatpercent(ans/final_total) End If ansImage = replace(ansPercent,"%","") ansImage = ansImage*2 ansdesc = rs2("ansdesc") Response.Write "<tr><td>" Response.Write "<i><font size='-3' color='black' face='verdana,arial,sans-serif'>" Response.Write ansdesc & "</font></i></td><td>" Response.Write "<i><font size='-3' color='black' face='verdana,arial,sans-serif'>" Response.Write ansPercent & "</font></i>" Response.Write "</td><td>" Response.Write "<img src = images/voter/char"& t &".gif width="& ansImage &" height=5></tr></td>" rs2.movenext t = t + 1 Loop Response.Write "</tr></td><tr><td colspan=3>" Response.Write "<b><font size='-2' color='black' face='verdana,arial,sans-serif'>" Response.Write "Всего голосовало: " & final_total & " человек</table>" Response.Write "</font></b>" %>
В заключение необходимо указать ряд упрощений, которые мы допустили. Во-первых, как читатель наверняка заметил, система разработана таким образом, что воспринимает не более пяти вариантов ответов на один и тот же вопрос. Мы не стали подробно останавливаться на механизме «ключиков», который использовался для регистрации уже ответившего пользователя. И еще, мы рассмотрели лишь один (частный) случай голосования по схеме «или» и опустили рассмотрение системы электронного голосования по схеме «и». Все эти и другие вопросы усовершенствования системы электронного голосования мы рассмотрим в одной из последующих публикаций настоящей статьи.
Однако разработанная нами система вполне приемлема для использования, а благодаря модульности ее реализации и описанному в статье подходу к ее внедрению в уже существующие сайты. Ее можно применить в качестве системы электронного голосования на сайте практически любой степени сложности.
С автором статьи можно связаться по адресу: rouben@iname.com.
КомпьютерПресс 10'2001